package gui;

import gui.houseeditor.HouseEditorPane;
import gui.houseeditor.HouseModel;
import gui.houseeditor.HouseModel.HouseObject;
import gui.houseeditor.strategies.HouseDrawStrategy;
import gui.houseeditor.strategies.MinimalisticHouseDrawStrategy;
import io.BaseHouseReader;
import io.HouseChars;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;

import org.jdesktop.swingx.JXTaskPane;
import org.jdesktop.swingx.JXTaskPaneContainer;
import org.jdesktop.swingx.decorator.ComponentAdapter;

import attori.controller.ControllerTemperaturaIF;
import attori.proattivi.Walker;

@SuppressWarnings("serial")
public class MainFrame extends JFrame {
	private JScrollPane centerPane;
	private HouseEditorPane housePane;
	private HouseModel model;
	private JXTaskPaneContainer sidebarUp;
	private JPanel sidebarDown;
	private File mapLocation;
	private DialogControlloTemperarature dialogTemperatura;
	private DialogSceltaPersonaggi dialogPersonaggi;
	private ControlloVolumeAction volume = new ControlloVolumeAction();
	private ControlloTemperaturaAction temperatura = new ControlloTemperaturaAction();
	private ControlloPersonaggiAction personaggi = new ControlloPersonaggiAction();
	private ControlloTemperaturaOptionAction temperaturaOption = new ControlloTemperaturaOptionAction();
	private AggiungiPersonaggioAction addAction = new AggiungiPersonaggioAction();
	private List<Walker> walkers;

	private class ResizeListener extends ComponentAdapter {
		@Override
		public void componentResized(ComponentEvent arg0) {
			housePane.setCellSize(Math.min(
					centerPane.getHeight() / model.getHeight(),
					centerPane.getWidth() / model.getWidth()));
		}
	}

	private class KeyHandler extends KeyAdapter {
		public void keyPressed(KeyEvent e) {
			int x = getPersonaX();
			int y = getPersonaY();
			int keyCode = e.getKeyCode();
			if ((x + 1) < model.getHeight() && keyCode == KeyEvent.VK_DOWN)
				if (model.getCell(x + 1, y) == HouseObject.BLANK) {
					model.setCell(HouseObject.BLANK, x, y);
					model.setCell(HouseObject.PERSONA, x + 1, y);
				}
			if (keyCode == KeyEvent.VK_UP)
				if ((x - 1) >= 0
						&& model.getCell(x - 1, y) == HouseObject.BLANK) {
					model.setCell(HouseObject.BLANK, x, y);
					model.setCell(HouseObject.PERSONA, x - 1, y);
				}
			if (keyCode == KeyEvent.VK_LEFT)
				if ((y - 1) >= 0
						&& model.getCell(x, y - 1) == HouseObject.BLANK) {
					model.setCell(HouseObject.BLANK, x, y);
					model.setCell(HouseObject.PERSONA, x, y - 1);
				}
			if (keyCode == KeyEvent.VK_RIGHT)
				if ((y + 1) < model.getWidth()
						&& model.getCell(x, y + 1) == HouseObject.BLANK) {
					model.setCell(HouseObject.BLANK, x, y);
					model.setCell(HouseObject.PERSONA, x, y + 1);
				}
		}
	}

	public MainFrame(File mapLocation) {
		super("Casa Intelligente");
		this.mapLocation = mapLocation;
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new BorderLayout());
		setIconImage(Toolkit.getDefaultToolkit().getImage("img/SuperMario.png"));
		initSidebar();
		initCenterPanel();
		housePane.repaint();
		model = housePane.getHouseModel();
		walkers = new LinkedList<Walker>();
		// Walker w = new Walker();
		// w.send(new Walker.Init(
		// model,
		// "3-6:DDRRDDRRRRRRDDDDRRRRDDDDDDDDDLLLLLLLLDRRRRRUUUUURRRRUUUUUUUULLLLLLLLLLLUUUUULLL",
		// 100));
		// walkers.add(w);
		// Walker w1 = new Walker();
		// w1.send(new Walker.Init(
		// model,
		// "3-6:DDRRDDRRRRRRDDDDRRRRDDDDDDDDDLLLLLLLLDRRRRRUUUUURRRRUUUUUUUULLLLLLLLLLLUUUUULLL",
		// 100));
		// walkers.add(w1);
		ResizeListener r = new ResizeListener();
		this.addComponentListener(r);
		setLocationByPlatform(true);
		pack();
		this.setExtendedState(Frame.MAXIMIZED_BOTH);
		housePane.setCellSize(Math.min(
				centerPane.getHeight() / model.getHeight(),
				centerPane.getWidth() / model.getWidth()));
		housePane.addKeyListener(new KeyHandler());
		housePane.requestFocusInWindow();
		housePane.setListenerForFocus();
		initWalkerList();
		repaint();
	}

	private void initCenterPanel() {
		try {
			readFromFile(mapLocation);
			housePane.setDrawable(false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("deprecation")
	private void initSidebar() {
		sidebarUp = new JXTaskPaneContainer();
		JXTaskPane pane = new JXTaskPane();
		pane.setTitle("Gestione Sensori");
		sidebarUp.add(pane);
		pane.add(volume);
		pane.add(temperatura);

		JXTaskPane pane1 = new JXTaskPane();
		pane1.setTitle("Gestione Personaggi");
		sidebarUp.add(pane1);
		pane1.add(personaggi);
		pane1.add(addAction);

		JXTaskPane pane2 = new JXTaskPane();
		pane2.setTitle("Gestione Temperatura");
		sidebarUp.add(pane2);
		pane2.add(temperaturaOption);

		sidebarDown = new JPanel();
		add(sidebarUp, BorderLayout.EAST);
		sidebarDown.setBackground(sidebarUp.getBackground());
		sidebarUp.setBackground(sidebarUp.getBackground());
	}

	private void readFromFile(File inFile) throws IOException {
		BaseHouseReader reader = new BaseHouseReader(new FileReader(inFile));
		HouseDrawStrategy strategy = new MinimalisticHouseDrawStrategy();
		housePane = new HouseEditorPane(reader.getWidth(), reader.getHeight(),
				strategy);
		dialogPersonaggi = new DialogSceltaPersonaggi(this, strategy);
		housePane.setCellSize(18);
		for (int i = 0; i < reader.getHeight(); i++)
			for (int j = 0; j < reader.getWidth(); j++) {
				switch (reader.get(i, j)) {
				case HouseChars.BLANK:
					housePane.getHouseModel().setCell(
							HouseModel.HouseObject.BLANK, i, j);
					break;

				case HouseChars.LAMPADINA:
					housePane.getHouseModel().setCell(
							HouseModel.HouseObject.LAMPADINA_SPENTA, i, j);
					break;

				case HouseChars.PORTA:
					housePane.getHouseModel().setCell(
							HouseModel.HouseObject.PORTA, i, j);
					break;

				case HouseChars.WALL:
					housePane.getHouseModel().setCell(
							HouseModel.HouseObject.WALL, i, j);
					break;

				case HouseChars.PERSONA:
					housePane.getHouseModel().setCell(
							HouseModel.HouseObject.PERSONA, i, j);
					break;
				}
			}
		centerPane = new JScrollPane(housePane);
		MainFrame.this.add(centerPane, BorderLayout.CENTER);
		MainFrame.this.validate();

	}

	private void initWalkerList() {
		sidebarDown.removeAll();
		for (int i = 0; i < walkers.size(); i++) {
			final Walker w = walkers.get(i);
			JLabel nameF = new JLabel("Walker " + (i + 1),
					SwingConstants.CENTER);
			sidebarDown.add(nameF);
			final JLabel ferma = new JLabel(new ImageIcon("img//play.png"));
			ferma.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
			ferma.addMouseListener(new MouseAdapter() {

				@Override
				public void mouseClicked(MouseEvent arg0) {
					if (w.currentStatus() == Walker.OPERATIVE) {
						w.send(new Walker.ToIdle());
						ferma.setIcon(new ImageIcon("img//pause.png"));
					} else if (w.currentStatus() == Walker.IDLE) {
						w.send(new Walker.ToOperative());
						ferma.setIcon(new ImageIcon("img//play.png"));
					}
				}
			});
			sidebarDown.add(ferma);
			final JLabel elimina = new JLabel(new ImageIcon("img//delete.png"));
			Cursor customCursor = Toolkit.getDefaultToolkit()
					.createCustomCursor(
							new ImageIcon("img//pistola.png").getImage(),
							new Point(0, 0), "customCursor");
			elimina.setCursor(customCursor);
			//
			elimina.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
			elimina.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseClicked(MouseEvent arg0) {
					walkers.remove(w);
					w.send(new Walker.AvadaKedavra());
					initWalkerList();
				}
			});
			sidebarDown.add(elimina);
		}
		add(sidebarDown, BorderLayout.SOUTH);
		if (getExtendedState() == Frame.MAXIMIZED_BOTH) {
			pack();
			this.setExtendedState(Frame.MAXIMIZED_BOTH);
		} else {
			pack();
		}
	}

	public int getPersonaY() {
		for (int i = 0; i < model.getHeight(); i++) {
			for (int j = 0; j < model.getWidth(); j++) {
				if (model.getCell(i, j) == HouseObject.PERSONA) {
					return j;
				}
			}
		}
		return -1;
	}

	public int getPersonaX() {
		for (int i = 0; i < model.getHeight(); i++) {
			for (int j = 0; j < model.getWidth(); j++) {
				if (model.getCell(i, j) == HouseObject.PERSONA) {
					return i;
				}
			}
		}
		return -1;
	}

	public HouseModel getHouseModel() {
		return model;
	}

	private class ControlloTemperaturaOptionAction extends AbstractAction {

		public ControlloTemperaturaOptionAction() {
			super("Controllo Temperatura");
			putValue(Action.SHORT_DESCRIPTION, "Scegli le temperature");
			putValue(Action.ACCELERATOR_KEY,
					KeyStroke.getKeyStroke("control V"));
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			dialogTemperatura.setVisible(true);
			housePane.requestFocusInWindow();
		}
	}

	private class ControlloPersonaggiAction extends AbstractAction {

		public ControlloPersonaggiAction() {
			super("Scelgi Immagine");
			putValue(Action.SHORT_DESCRIPTION,
					"Scelgi Immagine Per i Personaggi");
			putValue(Action.ACCELERATOR_KEY,
					KeyStroke.getKeyStroke("control V"));
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			dialogPersonaggi.setVisible(true);
			housePane.requestFocusInWindow();
		}
	}

	private class AggiungiPersonaggioAction extends AbstractAction {

		public AggiungiPersonaggioAction() {
			super("Nuovo personaggio");
			putValue(Action.SHORT_DESCRIPTION, "Scegli nuovo personaggio");
			putValue(Action.ACCELERATOR_KEY,
					KeyStroke.getKeyStroke("control V"));
		}

		@SuppressWarnings("deprecation")
		@Override
		public void actionPerformed(ActionEvent e) {
			JFileChooser fc = new JFileChooser(new File("mappe/"));
			int response = fc.showOpenDialog(MainFrame.this);
			if (response == JFileChooser.APPROVE_OPTION) {
				File f = fc.getSelectedFile();
				BufferedReader br;
				String percorso = null;

				try {
					br = new BufferedReader(new FileReader(f));
					percorso = br.readLine();
					br.close();
				} catch (Exception e1) {
					dispose();
				}

				if (f != null) {
					Walker w = new Walker();
					w.send(new Walker.Init(model, percorso, 400));
					walkers.add(w);
					initWalkerList();
				}
			} else if (response == JFileChooser.CANCEL_OPTION) {
				fc.disable();
			}
			housePane.requestFocusInWindow();
			sidebarDown.repaint();
		}
	}

	private class ControlloVolumeAction extends AbstractAction {

		public ControlloVolumeAction() {
			super("Sensori di Volume");
			putValue(Action.SHORT_DESCRIPTION, "Gestisci i sensori di volume");
			putValue(Action.ACCELERATOR_KEY,
					KeyStroke.getKeyStroke("control V"));
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			new DialogSensori(MainFrame.this, MainFrame.this.model,
					DialogSensori.VOLUME);
			housePane.requestFocusInWindow();
		}
	}

	private class ControlloTemperaturaAction extends AbstractAction {

		public ControlloTemperaturaAction() {
			super("Sensori di Temperatura");
			putValue(Action.SHORT_DESCRIPTION, "Gestisci i sensori di volume");
			putValue(Action.ACCELERATOR_KEY,
					KeyStroke.getKeyStroke("control V"));
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			new DialogSensori(MainFrame.this, MainFrame.this.model,
					DialogSensori.TEMPERATURA);
			housePane.requestFocusInWindow();
		}

	}

	public HouseEditorPane getHousePane() {
		return housePane;
	}

	public void setControllerTemperatura(
			List<ControllerTemperaturaIF> controllerTemperatura) {
		dialogTemperatura = new DialogControlloTemperarature(MainFrame.this,
				controllerTemperatura);
	}

	public void avadaKedavra(int i, int j) {

		List<Walker> walkersCopy = new LinkedList<Walker>();
		for (Walker w : walkers) {
			walkersCopy.add(w);
		}
		
		for (Walker w : walkersCopy) {
			if (i == w.getLastX() && j == w.getLastY()) {
				walkers.remove(w);
				w.send(new Walker.AvadaKedavra());
				initWalkerList();
			}
		}
	}
}
